/**
 * @overview
 * An extension of Max Bazhenov's Ext.ux.UploadDialog
 * http://www.max-bazhenov.com/dev/upload-dialog-2.0/index.php
 * @author Chris Scott
 */


/**
 * Ext.ux.UploadDialog.FileRecord
 * Re-define the UploadDialog grid's record.  add field baseParams for easier mapping to ActiveRecord
 */
Ext.ux.UploadDialog.FileRecord = Ext.data.Record.create([
  {name: 'baseParams'},
  {name: 'filename'},
  {name: 'state', type: 'int'},
  {name: 'note'},
  {name: 'input_element'}
]);
// NB:  DO NOT DELETE THESE.  WHEN UNDEFINED, UploadDialog's state-machine goes to shit.
Ext.ux.UploadDialog.FileRecord.STATE_QUEUE = 0;
Ext.ux.UploadDialog.FileRecord.STATE_FINISHED = 1;
Ext.ux.UploadDialog.FileRecord.STATE_FAILED = 2;
Ext.ux.UploadDialog.FileRecord.STATE_PROCESSING = 3;
Ext.ux.UploadDialog.FileRecord.STATE_LOCKED = 4    // <-- new WAITING STATE

/**
 * RExt.UploadDialog
 * @extends Ext.ux.UploadDialog.Dialog
 * add extensions to Ext.ux.UploadDialog.Dialog to make it more rails-y
 * @param {Object} browse_btn
 */
RExt.UploadDialog = Ext.extend(Ext.ux.UploadDialog.Dialog, {

    cls: 'x-hidden',

    /**
     * @cfg base_params [{}]
     */
    base_params : {},

    initComponent : function() {
        this.addEvents({
            /**
             * @event addrecord
             * fires just before record is added to store.  listen to modify record properties.
             * @param {Object} this
             * @param {Ext.ux.UploadDialog.FileRecord} record
             */
            addrecord : true
        });

        /*
        this.on('filevalid', function() {
            console.log('filevalid args ', arguments);
        });
        */

        RExt.UploadDialog.superclass.initComponent.call(this);
    },

    /**
     * addFileToUploadQueue
     * override to add baseParams field to Record.
     * @param {Object} browse_btn
     */
    addFileToUploadQueue : function(browse_btn, state) {

        var input_file = browse_btn.detachInputFile();
        input_file.appendTo(this.form);
        input_file.setStyle('width', '100px');
        input_file.dom.disabled = true;

        /**
         * @Dave says, we need to ensure we don't add the same file to the grid_panel more than once.
         * currently, you can add 111 copies of the same file to the upload queue which is not too smart.
         */

        if ( this.isDuplicate(input_file.dom.value) == -1) {
            //console.log('adding a record to the upload grid_panel store');
            // only change the state machine if the file is not a dupe
            state = state || Ext.ux.UploadDialog.FileRecord.STATE_QUEUE;  // <-- add with custom STATE

            var store = this.grid_panel.getStore();
            var record = new Ext.ux.UploadDialog.FileRecord({
                state: Ext.ux.UploadDialog.FileRecord.STATE_QUEUE,
                filename: input_file.dom.value,
                baseParams: {
                    model: browse_btn.model
                },
                note: this.i18n.note_queued_to_upload,
                input_element: input_file
            });

            // @chris fire addrecord event to give adder a chance to modify params.
            this.fireEvent('addrecord', this, record);
            store.add(record);
            //this.fsa.postEvent('file-added', input_file.dom.value);
        } else {
            console.log('the desired file was not added to the grid_panel store');
        }
        this.fsa.postEvent('file-added', input_file.dom.value);
    },

    /**
     * isDuplicate
     * @Dave
     * returns index of the provided file from the store.. -1 if not found
     * @param {String} file
     */
    isDuplicate : function (file) {
        var store = this.grid_panel.getStore();
        return store.find('filename', file);
    },

    /**
     * setBaseParams
     * Override to Ext.apply baseParams rather than directly setting, so that incoming baseParams will be combined wiht existing
     * this.base_params = params vs this.base_params = Ext.apply(this.base_params, params)
     * @param {Object} params
     */
    setBaseParams : function(params) {
        this.base_params = Ext.apply(this.base_params, params); // <-- Ext.apply instead.
    }
});

/**
 * RExt.UploadMgr
 * @singleton
 * Manages Ext.ux.UploadDialog to act more as an "upload service" and work behind the scenes instead of being operated upon directly.
 * @author Chris Scott
 *
 */
 RExt.UploadMgr = (function() {

    /**
     *  since the isPermittedFile check does not effectively allow us to clear the combo box
     *  I hacked this stupid variable in till I can get a better grip on how this machine works
     */
    var valid_file  = false;

    // create UploadDialog instance.
    var dialog = new RExt.UploadDialog({
        id: 'upload_dialog',
        title: 'File uploader',
        resizable: false,
        width: 400,
        height: 400,
        minHeight: 1,
        minWidth: 1,
        constrain: false,
        shadow: false,
        //x: 10000,
        //y: 10000,
        renderTo: document.body,
        url: 'file/upload',
        reset_on_hide: false,
        allow_close_on_upload: true,
        upload_autostart: false,
        listeners : {

            /**
             * @event beforeupload
             * attach Record's baseParams to Dialog so they get sent with Ajax request.
             * @param {Object} d
             * @param {Object} rec
             */
            beforefileuploadstart : function(d, filename, rec) {
                console.log('before rec: ', rec);
                d.setBaseParams(rec.data.baseParams);
            },
            /**
             * @event uploadsuccess
             * @param {Object} d
             * @param {Object} filename
             * @param {Object} data
             * @param {Object} record
             */
            uploadsuccess : function(d, filename, data, record) {
                console.log('the wrong uploadsuccess is firing... ');
                App.setAlert(App.STATUS_OK, 'Uploaded ' + filename);
            },
            /**
             * @event uploaderror
             * @param {Object} d
             * @param {Object} filename
             * @param {Object} data
             * @param {Object} record
             */
            uploaderror : function(d, filename, data, record) {
                App.setAlert(App.STATUS_ERROR, 'Error uploading file "' + filename + '"');
            },
            /**
             * @event uploadfailed
             * @param {Object} d
             * @param {Object} filename
             * @param {Object} record
             */
            uploadfailed : function(d, filename, record) {
                App.setAlert(App.STATUS_ERROR, 'Upload failed on "' + filename + '"');
            },

            addrecord : function(d, record) {
                record.set('state', RExt.UploadMgr.state);
                console.log('addrecord: ', record.data.state);
            },

            /**
             * @event filevalid
             * this is a hack.. we simply use this to toggle a variable that we can use to
             * help the UploadMgr set the value of only valid files instead of invalid ones.
             * Strictly a cosmetic punch in the head.
             * @param {Object} d
             * @param {Object} status
             */
            filevalid: function(d, status) {
                valid_file = status;
            }

        }
    });
    App.onReady(function() {
        dialog.show();
        dialog.hide();
    });

    return {
        PERMITTED_EXTENSIONS_VIDEO : ['avi', 'mpg', 'mpeg', 'mp4', 'flv', 'wmv'],
        PERMITTED_EXTENSIONS_IMAGE : ['jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'png'],
        PERMITTED_EXTENSIONS_DOCUMENT : ['doc', 'pdf', 'zip'],

        state : Ext.ux.UploadDialog.FileRecord.STATE_QUEUE,

        /**
         * add
         * Adds a file to UploadMgr
         * @param {Ext.ux.form.BrowseButton} btn the Browse button instance.  this instance contains the <input type="file" /> field.
         */
        add : function(btn, state) {
            this.state = state || Ext.ux.UploadDialog.FileRecord.STATE_QUEUE;
            dialog.fsa.postEvent('file-selected', btn);
            return valid_file;    // hacked this in to assist the onSelect function with decisions
        },

        /**
         * flush
         * flush the upload Queue.  uploads all files in queue.
         * @param {function} callback
         * @param {scope} scope
         * @param {Boolean} releaseLocks [false] true to flush locked files (Ext.ux.UploadDialog.FileRecord::STATE_LOCKED
         */
        flush : function(callback, scope, releaseLocks) {
            releaseLocks = releaseLocks || false;

            console.info("RExt.UploadMgr::flush() callback %o, scope: %o, releaseLocks %o", callback, scope, releaseLocks);
            if (releaseLocks == true) {
                var store = dialog.grid_panel.getStore();
                store.each(function(r) {
                    if (r.data.state == Ext.ux.UploadDialog.FileRecord.STATE_LOCKED) {
                        r.beginEdit();
                        r.set('state', Ext.ux.UploadDialog.FileRecord.STATE_QUEUE);
                        r.endEdit();
                    }
                });
            }
            if (dialog.hasListener('uploadsuccess')) {
                console.info('dialog has an uploadsuccess listener... so we clear it to do this one instead');
                dialog.events['uploadsuccess'].clearListeners();
            }
            console.log("assigning a new listener to the dialog -- uploadsuccess %o", dialog.events['uploadsuccess']);
            dialog.on('uploadsuccess', function(d, filename, data, record) {
                console.log('RExt.UploadMgr.dialog::uploadsuccess processing...');
                if (typeof(callback) == 'function') {
                    //TODO: change this signature to perhaps just respond with the data argument for the callback
                    callback.call(scope, d, filename, data, record);
                } else {
                    console.warn("No callback function defined...");
                }
            },this);

            dialog.startUpload();
        },

        /**
         * setUrl
         * set the Ext.ux.UploadDialog's upload url.  you should always set this in your index page.
         * @param {Object} url
         */
        setUrl : function(url) {
            dialog.setUrl(url);
        },

        /**
         * setPermittedExtensions
         * @param {Array}
         */
        setPermittedExtensions : function(list) {
            dialog.setPermittedExtensions(list);
        },

        /**
         * allowOnly
         * shortcut to setPermittedExtensions for 'image' / 'images', 'document' / 'documents'
         * @param {Object} type
         * @throws Error
         */
        allowOnly : function(type) {
            switch (type) {
                case 'video':
                case 'videos':
                    dialog.setPermittedExtensions(RExt.UploadMgr.PERMITTED_EXTENSIONS_VIDEO);
                    break;
                case 'image':
                case 'images':
                    dialog.setPermittedExtensions(RExt.UploadMgr.PERMITTED_EXTENSIONS_IMAGE);
                    break;
                case 'document':
                case 'documents':
                    dialog.setPermittedExtensions(this.PERMITTED_EXTENSIONS_DOCUMENT);
                    break;
                case 'all':
                    dialog.setPermittedExtensions([]);
                    break;
                default:
                    throw Error('RExt.UploadMgr::allowOnly supplied with unknown type "' + type + '"');
                    break;
            }
        },

        /**
         * getDialog
         * @return {
         */
        getDialog : function() { return dialog; },

        getValid : function () { return valid_file;}
    };

 })();
